from Data_Type import *
from MEMORY import *
from Register_File import *
from IF import *
from ID import *
from system import *

def EX(micro_opt : micro_option, Rs1: register, Rs2: register, imm:int, pc: register, mem: Memory, RF:register_file, mmu):
    ex2reg_value = 0
    ex2mem_value = 0
    addr = 0
    EXIT = False

    if micro_opt.name == "add" :
        ex2reg_value = Rs1.value + Rs2.value
    if micro_opt.name == "sub" :
        ex2reg_value = Rs1.value - Rs2.value
    if micro_opt.name == "mul" :
        ex2reg_value = Rs1.value * Rs2.value
    if micro_opt.name == "xor" :
        ex2reg_value = Rs1.value ^ Rs2.value
    if micro_opt.name == "or" :
        ex2reg_value = Rs1.value | Rs2.value
    if micro_opt.name == "sll" :
        ex2reg_value = Rs1.value << Rs2.value
    if micro_opt.name == "addi":
        ex2reg_value = Rs1.value + imm
    if micro_opt.name == "xori":
        ex2reg_value = Rs1.value ^ imm
    if micro_opt.name == "andi":
        ex2reg_value = Rs1.value & imm
    if micro_opt.name == "ori":
        ex2reg_value = Rs1.value | imm
    if micro_opt.name == "slli":
        ex2reg_value = Rs1.value << imm
    if micro_opt.name == "rem":
        ex2reg_value = Rs1.value % Rs2.value
    if micro_opt.name == "div":
        ex2reg_value = Rs1.value // Rs2.value


    if micro_opt.name == "lb":
        addr = Rs1.value + imm
    if micro_opt.name == "lh":
        addr = Rs1.value + imm
    if micro_opt.name == "lw":
        addr = Rs1.value + imm
    if micro_opt.name == "lbu":
        addr = Rs1.value + imm
    if micro_opt.name == "lhu":
        addr = Rs1.value + imm
    if micro_opt.name == "lwu":
        addr = Rs1.value + imm

    if micro_opt.name == "sb":
        ex2mem_value = Rs2.value
        addr = Rs1.value + imm
    if micro_opt.name == "sh":
        ex2mem_value = Rs2.value
        addr = Rs1.value + imm
    if micro_opt.name == "sw":
        ex2mem_value = Rs2.value
        addr = Rs1.value + imm
    
    if micro_opt.name == "ecall":
        # print("ecall happend")
        sys_call(RF.files[10].value,RF.files[11].value,RF.files[12].value,RF.files[13].value,RF.files[14].value,RF.files[15].value,RF.files[16].value,RF.files[17].value,mem,mmu)

    if micro_opt.name == "lui":
        ex2reg_value = imm

    if micro_opt.name == "auipc":
        ex2reg_value = pc.value + imm

    if micro_opt.jump:
        if micro_opt.name == "jal":
            ex2reg_value = pc.value + 0x4
            pc.set(pc.value + imm)
        elif micro_opt.name == "jalr":
            ex2reg_value = pc.value + 0x4
            pc.set((Rs1.value + imm)&(~1))
        elif micro_opt.name == "beq":
            if Rs1.value == Rs2.value:
                pc.set(pc.value + imm)
            else:
                pc.set(pc.value + 0x4)
        elif micro_opt.name == "bne":
            if Rs1.value != Rs2.value:
                pc.set(pc.value + imm)
            else:
                pc.set(pc.value + 0x4)
        elif micro_opt.name == "blt":
            if micro_opt.unsigned:
                if Rs1.value < Rs2.value:
                    pc.set(pc.value + imm)
                else:
                    pc.set(pc.value + 0x4)
            else:
                if sign_expend(Rs1.value, 32) < sign_expend(Rs2.value, 32):
                    pc.set(pc.value + imm)
                else:
                    pc.set(pc.value + 0x4)
        elif micro_opt.name == "bge":
            if micro_opt.unsigned:
                if Rs1.value >= Rs2.value:
                    pc.set(pc.value + imm)
                else:
                    pc.set(pc.value + 0x4)
            else:
                if sign_expend(Rs1.value, 32) >= sign_expend(Rs2.value, 32):
                    pc.set(pc.value + imm)
                else:
                    pc.set(pc.value + 0x4)
        
    else:
        pc.set(pc.value + 0x4)
    return micro_opt, ex2reg_value, ex2mem_value, addr, pc